﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MongoServices.Tests.TestHelpers;
using Xunit;
using Moq;
using MongoServices.Tests.Stubs;
using MongoDB.Bson;

namespace MongoServices.Tests.ReadOnlyServiceTests
{
	public class ReadOnlyServiceTests : TestBase
	{
		protected ObjectId Id1 { get; private set; }
		protected ObjectId Id2 { get; private set; }
		protected ObjectId Id3 { get; private set; }

		protected TestModelSimple TestModel1 { get; private set; }
		protected TestModelSimple TestModel2 { get; private set; }
		protected TestModelSimple TestModel3 { get; private set; }

		protected IEnumerable<TestModelSimple> TestModelCollection { get; private set; }

		protected Mock<IReadOnlyRepository<TestModelSimple>> ReadOnlyRepositoryMock { get; private set; }
		protected ReadOnlyService<TestModelSimple> ReadOnlyServiceTestModelSimple { get; private set; }

		public ReadOnlyServiceTests()
		{
			Setup();
		}

		public void Setup()
		{
			Id1 = ObjectId.GenerateNewId();
			Id2 = ObjectId.GenerateNewId();
			Id2 = ObjectId.GenerateNewId();

			TestModel1 = new TestModelSimple { Id = Id1 };
			TestModel2 = new TestModelSimple { Id = Id2 };
			TestModel3 = new TestModelSimple { Id = Id3 };

			TestModelCollection = new List<TestModelSimple> {
						 TestModel1,
						 TestModel2,
						 TestModel3
			};

			ReadOnlyRepositoryMock = new Mock<IReadOnlyRepository<TestModelSimple>>();
			ReadOnlyServiceTestModelSimple = new ReadOnlyServiceTestModelSimpleStub(ReadOnlyRepositoryMock.Object);
		}
	}

	public class WhenGetAllIsCalled : ReadOnlyServiceTests
	{
		[Fact]
		public void RepositoryGetAllMethodIsCalledOnce()
		{
			ReadOnlyServiceTestModelSimple.GetAll();

			ReadOnlyRepositoryMock.Verify(m => m.GetAll(), Times.Once());
		}

		[Fact]
		public void TheSameCollectionIsReturnedFromTheRepositoryGetAllMethod()
		{
			ReadOnlyRepositoryMock.Setup(m => m.GetAll()).Returns(TestModelCollection);

			Assert.Same(TestModelCollection, ReadOnlyServiceTestModelSimple.GetAll());
		}
	}

	public class WhenGetByIdIsCalled : ReadOnlyServiceTests
	{
		[Fact]
		public void RepositoryGetByIdMethodIsCalledOnce()
		{
			var id = ObjectId.GenerateNewId();

			var results = ReadOnlyServiceTestModelSimple.GetById(id);

			ReadOnlyRepositoryMock.Verify(m => m.GetById(It.Is<ObjectId>(o => o == id)), Times.Once());
		}

		[Fact]
		public void TheSameModelIsReturnedFromTheRepositoryGetByIdMethod()
		{
			ReadOnlyRepositoryMock.Setup(m => m.GetById(It.IsAny<ObjectId>())).Returns<ObjectId>(id => TestModelCollection.First(m => m.Id == id));

			Assert.Same(TestModelCollection.First(m => m.Id == Id2), ReadOnlyServiceTestModelSimple.GetById(Id2));
		}
	}
}
